#ifndef PR_GS2DEX_H
#define PR_GS2DEX_H

#include "ultratypes.h"
#include <libultraship/libultra/gs2dex.h>

#if 0
#ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" {
#endif

/*===========================================================================*
 *	Macro
 *===========================================================================*/
#define GS_CALC_DXT(line) (((1 << G_TX_DXT_FRAC) - 1) / (line) + 1)
#define GS_PIX2TMEM(pix, siz) ((pix) >> (4 - (siz)))
#define GS_PIX2DXT(pix, siz) GS_CALC_DXT(GS_PIX2TMEM((pix), (siz)))

/*===========================================================================*
 *	Data structures for S2DEX microcode
 *===========================================================================*/

/*---------------------------------------------------------------------------*
 *	Background
 *---------------------------------------------------------------------------*/
#define G_BGLT_LOADBLOCK 0x0033
#define G_BGLT_LOADTILE 0xFFF4

#define G_BG_FLAG_FLIPS 0x01
#define G_BG_FLAG_FLIPT 0x10

/* Non scalable background plane */
typedef	struct	{
  u16   imageX;		/* x-coordinate of upper-left position of texture (u10.5) */
  u16	imageW;		/* width of the texture (u10.2) */
  s16	frameX;		/* upper-left position of transferred frame (s10.2) */
  u16	frameW;		/* width of transferred frame (u10.2) */

  u16   imageY; 	/* y-coordinate of upper-left position of texture (u10.5) */
  u16	imageH;		/* height of the texture (u10.2) */
  s16	frameY;		/* upper-left position of transferred frame (s10.2) */
  u16	frameH;		/* height of transferred frame (u10.2) */

  u64  *imagePtr;	/* texture source address on DRAM */
  u16	imageLoad;	/* which to use, LoadBlock or  LoadTile */
  u8	imageFmt;	/* format of texel - G_IM_FMT_*  */
  u8	imageSiz;	/* size of texel - G_IM_SIZ_*   */
  u16   imagePal; 	/* pallet number  */
  u16	imageFlip;	/* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */

  /* The following is set in the initialization routine guS2DInitBg(). There is no need for the user to set it. */
  u16	tmemW;		/* TMEM width and Word size of frame 1 line.
                           At LoadBlock, GS_PIX2TMEM(imageW/4,imageSiz)
                           At LoadTile  GS_PIX2TMEM(frameW/4,imageSiz)+1 */
  u16	tmemH;		/* height of TMEM loadable at a time (s13.2) 4 times value
			   When the normal texture, 512/tmemW*4
			   When the CI texture, 256/tmemW*4 */
  u16	tmemLoadSH;	/* SH value
			   At LoadBlock, tmemSize/2-1
			   At LoadTile, tmemW*16-1 */
  u16	tmemLoadTH;	/* TH value or Stride value
			   At LoadBlock, GS_CALC_DXT(tmemW)
			   At LoadTile, tmemH-1 */
  u16	tmemSizeW;	/* skip value of imagePtr for image 1-line
			   At LoadBlock, tmemW*2
                           At LoadTile, GS_PIX2TMEM(imageW/4,imageSiz)*2 */
  u16	tmemSize;	/* skip value of imagePtr for 1-loading
			   = tmemSizeW*tmemH                          */
} uObjBg_t;		/* 40 bytes */

/* Scalable background plane */
typedef	struct	{
  u16   imageX;		/* x-coordinate of upper-left position of texture (u10.5) */
  u16	imageW;		/* width of texture (u10.2) */
  s16	frameX;		/* upper-left position of transferred frame (s10.2) */
  u16	frameW;		/* width of transferred frame (u10.2) */

  u16   imageY; 	/* y-coordinate of upper-left position of texture (u10.5) */
  u16	imageH;		/* height of texture (u10.2) */
  s16	frameY;		/* upper-left position of transferred frame (s10.2) */
  u16	frameH;		/* height of transferred frame (u10.2) */

  u64  *imagePtr;	/* texture source address on DRAM */
  u16	imageLoad;	/* Which to use, LoadBlock or LoadTile? */
  u8	imageFmt;	/* format of texel - G_IM_FMT_*  */
  u8	imageSiz;	/* size of texel - G_IM_SIZ_*  */
  u16   imagePal; 	/* pallet number */
  u16	imageFlip;	/* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */

  u16	scaleW;		/* scale value of X-direction (u5.10) */
  u16	scaleH;		/* scale value of Y-direction (u5.10) */
  s32	imageYorig;	/* start point of drawing on image (s20.5) */

  u8	padding[4];

} uObjScaleBg_t;	/* 40 bytes */

typedef union {
  uObjBg_t        b;
  uObjScaleBg_t   s;
  long long int   force_structure_alignment;
} uObjBg;

/*---------------------------------------------------------------------------*
 *	2D Objects
 *---------------------------------------------------------------------------*/
#define G_OBJ_FLAG_FLIPS 1 << 0 /* inversion to S-direction */
#define G_OBJ_FLAG_FLIPT 1 << 4 /* nversion to T-direction */

typedef struct {
  s16  objX;		/* s10.2 OBJ x-coordinate of upper-left end */
  u16  scaleW;		/* u5.10 Scaling of u5.10 width direction   */
  u16  imageW;		/* u10.5 width of u10.5 texture (length of S-direction) */
  u16  paddingX;	/* Unused - Always 0 */
  s16  objY;		/* s10.2 OBJ y-coordinate of s10.2 OBJ upper-left end */
  u16  scaleH;		/* u5.10 Scaling of u5.10 height direction */
  u16  imageH;		/* u10.5 height of u10.5 texture (length of T-direction) */
  u16  paddingY;	/* Unused - Always 0 */
  u16  imageStride;	/* folding width of texel (In units of 64bit word) */
  u16  imageAdrs;	/* texture header position in TMEM (In units of 64bit word) */
  u8   imageFmt;	/* format of texel - G_IM_FMT_* */
  u8   imageSiz;	/* size of texel - G_IM_SIZ_* */
  u8   imagePal;	/* pallet number (0-7) */
  u8   imageFlags;	/* The display flag - G_OBJ_FLAG_FLIP* */
} uObjSprite_t;		/* 24 bytes */

typedef union {
  uObjSprite_t      s;
  long long int   force_structure_alignment;
} uObjSprite;

/*---------------------------------------------------------------------------*
 *	2D Matrix
 *---------------------------------------------------------------------------*/
typedef struct {
  s32   A, B, C, D;     /* s15.16 */
  s16   X, Y;           /* s10.2  */
  u16   BaseScaleX;	/* u5.10  */
  u16   BaseScaleY;	/* u5.10  */
} uObjMtx_t;		/* 24 bytes */

typedef union {
  uObjMtx_t	m;
  long long int force_structure_alignment;
} uObjMtx;

typedef struct {
  s16   X, Y;           /* s10.2  */
  u16   BaseScaleX;	/* u5.10  */
  u16   BaseScaleY;	/* u5.10  */
} uObjSubMtx_t;		/* 8 bytes */

typedef union {
  uObjSubMtx_t	m;
  long long int force_structure_alignment;
} uObjSubMtx;

/*---------------------------------------------------------------------------*
 *	Loading into TMEM
 *---------------------------------------------------------------------------*/
#define G_OBJLT_TXTRBLOCK 0x00001033
#define G_OBJLT_TXTRTILE 0x00FC1034
#define G_OBJLT_TLUT 0x00000030

#define GS_TB_TSIZE(pix, siz) (GS_PIX2TMEM((pix), (siz)) - 1)
#define GS_TB_TLINE(pix, siz) (GS_CALC_DXT(GS_PIX2TMEM((pix), (siz))))

typedef	struct	{
  u32	type;		/* G_OBJLT_TXTRBLOCK divided into types */
  u64	*image;		/* texture source address on DRAM */
  u16	tmem;		/* loaded TMEM word address (8byteWORD) */
  u16	tsize;		/* Texture size, Specified by macro GS_TB_TSIZE() */
  u16	tline;		/* width of Texture 1-line, Specified by macro GS_TB_TLINE() */
  u16	sid;		/* STATE ID Multipled by 4 (Either one of  0, 4, 8 and 12) */
  u32	flag;		/* STATE flag  */
  u32	mask;		/* STATE mask  */
} uObjTxtrBlock_t;		/* 24 bytes */

#define GS_TT_TWIDTH(pix, siz) ((GS_PIX2TMEM((pix), (siz)) << 2) - 1)
#define GS_TT_THEIGHT(pix, siz) (((pix) << 2) - 1)

typedef	struct	{
  u32	type;		/* G_OBJLT_TXTRTILE divided into types */
  u64	*image;		/* texture source address on DRAM */
  u16	tmem;		/* loaded TMEM word address (8byteWORD)*/
  u16	twidth;		/* width of Texture (Specified by macro GS_TT_TWIDTH()) */
  u16	theight;	/* height of Texture (Specified by macro GS_TT_THEIGHT()) */
  u16	sid;		/* STATE ID Multipled by 4 (Either one of  0, 4, 8 and 12) */
  u32	flag;		/* STATE flag  */
  u32	mask;		/* STATE mask  */
} uObjTxtrTile_t;		/* 24 bytes */

#define GS_PAL_HEAD(head) ((head) + 256)
#define GS_PAL_NUM(num) ((num)-1)

typedef	struct	{
  u32	type;		/* G_OBJLT_TLUT divided into types */
  u64	*image;		/* texture source address on DRAM */
  u16	phead;		/* pallet number of load header (Between 256 and 511) */
  u16	pnum;		/* loading pallet number -1 */
  u16   zero;		/* Assign 0 all the time */
  u16	sid;		/* STATE ID Multipled by 4 (Either one of  0, 4, 8 and 12)*/
  u32	flag;		/* STATE flag  */
  u32	mask;		/* STATE mask  */
} uObjTxtrTLUT_t;		/* 24 bytes */

typedef union {
  uObjTxtrBlock_t      block;
  uObjTxtrTile_t       tile;
  uObjTxtrTLUT_t       tlut;
  long long int   force_structure_alignment;
} uObjTxtr;

/*---------------------------------------------------------------------------*
 *	Loading into TMEM & 2D Objects
 *---------------------------------------------------------------------------*/
typedef	struct	{
  uObjTxtr	txtr;
  uObjSprite	sprite;
} uObjTxSprite;		/* 48 bytes */

/*===========================================================================*
 *	GBI Commands for S2DEX microcode
 *===========================================================================*/
/* GBI Header */
#ifdef F3DEX_GBI_2
#define G_OBJ_RECTANGLE_R 0xDA
#define G_OBJ_MOVEMEM 0xDC
#define G_RDPHALF_0 0xE4
#define G_OBJ_RECTANGLE 0x01
#define G_OBJ_SPRITE 0x02
#define G_SELECT_DL 0x04
#define G_OBJ_LOADTXTR 0x05
#define G_OBJ_LDTX_SPRITE 0x06
#define G_OBJ_LDTX_RECT 0x07
#define G_OBJ_LDTX_RECT_R 0x08
#define G_BG_1CYC 0x09
#define G_BG_COPY 0x0A
#define G_OBJ_RENDERMODE 0x0B
#else
#define G_BG_1CYC 0x01
#define G_BG_COPY 0x02
#define G_OBJ_RECTANGLE 0x03
#define G_OBJ_SPRITE 0x04
#define G_OBJ_MOVEMEM 0x05
#define G_SELECT_DL 0xB0
#define G_OBJ_RENDERMODE 0xB1
#define G_OBJ_RECTANGLE_R 0xB2
#define G_OBJ_LOADTXTR 0xC1
#define G_OBJ_LDTX_SPRITE 0xC2
#define G_OBJ_LDTX_RECT 0xC3
#define G_OBJ_LDTX_RECT_R 0xC4
#define G_RDPHALF_0 0xE4
#endif

/*---------------------------------------------------------------------------*
 *	Background wrapped screen
 *---------------------------------------------------------------------------*/
#define gSPBgRectangle(pkt, m, mptr) gDma0p((pkt), (m), (mptr), 0)
#define gsSPBgRectangle(m, mptr) gsDma0p((m), (mptr), 0)
#define gSPBgRectCopy(pkt, mptr) gSPBgRectangle((pkt), G_BG_COPY, (mptr))
#define gsSPBgRectCopy(mptr) gsSPBgRectangle(G_BG_COPY, (mptr))
#define gSPBgRect1Cyc(pkt, mptr) gSPBgRectangle((pkt), G_BG_1CYC, (mptr))
#define gsSPBgRect1Cyc(mptr) gsSPBgRectangle(G_BG_1CYC, (mptr))

/*---------------------------------------------------------------------------*
 *	2D Objects
 *---------------------------------------------------------------------------*/
#define gSPObjSprite(pkt, mptr) gDma0p((pkt), G_OBJ_SPRITE, (mptr), 0)
#define gsSPObjSprite(mptr) gsDma0p(G_OBJ_SPRITE, (mptr), 0)
#define gSPObjRectangle(pkt, mptr) gDma0p((pkt), G_OBJ_RECTANGLE, (mptr), 0)
#define gsSPObjRectangle(mptr) gsDma0p(G_OBJ_RECTANGLE, (mptr), 0)
#define gSPObjRectangleR(pkt, mptr) gDma0p((pkt), G_OBJ_RECTANGLE_R, (mptr), 0)
#define gsSPObjRectangleR(mptr) gsDma0p(G_OBJ_RECTANGLE_R, (mptr), 0)

/*---------------------------------------------------------------------------*
 *	2D Matrix
 *---------------------------------------------------------------------------*/
#define gSPObjMatrix(pkt, mptr) gDma1p((pkt), G_OBJ_MOVEMEM, (mptr), 0, 23)
#define gsSPObjMatrix(mptr) gsDma1p(G_OBJ_MOVEMEM, (mptr), 0, 23)
#define gSPObjSubMatrix(pkt, mptr) gDma1p((pkt), G_OBJ_MOVEMEM, (mptr), 2, 7)
#define gsSPObjSubMatrix(mptr) gsDma1p(G_OBJ_MOVEMEM, (mptr), 2, 7)

/*---------------------------------------------------------------------------*
 *	Loading into TMEM
 *---------------------------------------------------------------------------*/
#define gSPObjLoadTxtr(pkt, tptr) gDma0p((pkt), G_OBJ_LOADTXTR, (tptr), 23)
#define gsSPObjLoadTxtr(tptr) gsDma0p(G_OBJ_LOADTXTR, (tptr), 23)
#define gSPObjLoadTxSprite(pkt, tptr) gDma0p((pkt), G_OBJ_LDTX_SPRITE, (tptr), 47)
#define gsSPObjLoadTxSprite(tptr) gsDma0p(G_OBJ_LDTX_SPRITE, (tptr), 47)
#define gSPObjLoadTxRect(pkt, tptr) gDma0p((pkt), G_OBJ_LDTX_RECT, (tptr), 47)
#define gsSPObjLoadTxRect(tptr) gsDma0p(G_OBJ_LDTX_RECT, (tptr), 47)
#define gSPObjLoadTxRectR(pkt, tptr) gDma0p((pkt), G_OBJ_LDTX_RECT_R, (tptr), 47)
#define gsSPObjLoadTxRectR(tptr) gsDma0p(G_OBJ_LDTX_RECT_R, (tptr), 47)

/*---------------------------------------------------------------------------*
 *	Select Display List
 *---------------------------------------------------------------------------*/
#define gSPSelectDL(pkt, mptr, sid, flag, mask)                           \
    {                                                                     \
        gDma1p((pkt), G_RDPHALF_0, (flag), (u32)(mptr)&0xFFFF, (sid));    \
        gDma1p((pkt), G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_PUSH); \
    }
#define gsSPSelectDL(mptr, sid, flag, mask)                         \
    {                                                               \
        gsDma1p(G_RDPHALF_0, (flag), (u32)(mptr)&0xFFFF, (sid));    \
        gsDma1p(G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_PUSH); \
    }
#define gSPSelectBranchDL(pkt, mptr, sid, flag, mask)                       \
    {                                                                       \
        gDma1p((pkt), G_RDPHALF_0, (flag), (u32)(mptr)&0xFFFF, (sid));      \
        gDma1p((pkt), G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_NOPUSH); \
    }
#define gsSPSelectBranchDL(mptr, sid, flag, mask)                     \
    {                                                                 \
        gsDma1p(G_RDPHALF_0, (flag), (u32)(mptr)&0xFFFF, (sid));      \
        gsDma1p(G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_NOPUSH); \
    }

/*---------------------------------------------------------------------------*
 *	Set general status
 *---------------------------------------------------------------------------*/
#define G_MW_GENSTAT 0x08 /* Note that it is the same value of G_MW_FOG */

#define gSPSetStatus(pkt, sid, val) gMoveWd((pkt), G_MW_GENSTAT, (sid), (val))
#define gsSPSetStatus(sid, val) gsMoveWd(G_MW_GENSTAT, (sid), (val))

/*---------------------------------------------------------------------------*
 *	Set Object Render Mode
 *---------------------------------------------------------------------------*/
#define G_OBJRM_NOTXCLAMP 0x01
#define G_OBJRM_XLU 0x02       /* Ignored */
#define G_OBJRM_ANTIALIAS 0x04 /* Ignored */
#define G_OBJRM_BILERP 0x08
#define G_OBJRM_SHRINKSIZE_1 0x10
#define G_OBJRM_SHRINKSIZE_2 0x20
#define G_OBJRM_WIDEN 0x40

#define gSPObjRenderMode(pkt, mode) gImmp1((pkt), G_OBJ_RENDERMODE, (mode))
#define gsSPObjRenderMode(mode) gsImmp1(G_OBJ_RENDERMODE, (mode))

/*===========================================================================*
 *	Render Mode Macro
 *===========================================================================*/
#define RM_RA_SPRITE(clk)                                                        \
    AA_EN | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \
        GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define G_RM_SPRITE G_RM_OPA_SURF
#define G_RM_SPRITE2 G_RM_OPA_SURF2
#define G_RM_RA_SPRITE RM_RA_SPRITE(1)
#define G_RM_RA_SPRITE2 RM_RA_SPRITE(2)
#define G_RM_AA_SPRITE G_RM_AA_TEX_TERR
#define G_RM_AA_SPRITE2 G_RM_AA_TEX_TERR2
#define G_RM_XLU_SPRITE G_RM_XLU_SURF
#define G_RM_XLU_SPRITE2 G_RM_XLU_SURF2
#define G_RM_AA_XLU_SPRITE G_RM_AA_XLU_SURF
#define G_RM_AA_XLU_SPRITE2 G_RM_AA_XLU_SURF2

/*===========================================================================*
 *	External functions
 *===========================================================================*/
extern	u64	gspS2DEX_fifoTextStart[], gspS2DEX_fifoTextEnd[];
extern	u64	gspS2DEX_fifoDataStart[], gspS2DEX_fifoDataEnd[];
extern	u64	gspS2DEX_fifo_dTextStart[], gspS2DEX_fifo_dTextEnd[];
extern	u64	gspS2DEX_fifo_dDataStart[], gspS2DEX_fifo_dDataEnd[];
extern	u64	gspS2DEX2_fifoTextStart[], gspS2DEX2_fifoTextEnd[];
extern	u64	gspS2DEX2_fifoDataStart[], gspS2DEX2_fifoDataEnd[];
extern	u64	gspS2DEX2_xbusTextStart[], gspS2DEX2_xbusTextEnd[];
extern	u64	gspS2DEX2_xbusDataStart[], gspS2DEX2_xbusDataEnd[];
extern	void	guS2DInitBg(uObjBg *);

#ifdef F3DEX_GBI_2
#define guS2DEmuBgRect1Cyc guS2D2EmuBgRect1Cyc /*Wrapper*/
#define guS2DEmuSetScissor guS2D2EmuSetScissor /*Wrapper*/
  extern void	guS2D2EmuSetScissor(u32, u32, u32, u32, u8);
  extern void	guS2D2EmuBgRect1Cyc(Gfx **, uObjBg *);
#else
  extern void	guS2DEmuSetScissor(u32, u32, u32, u32, u8);
  extern void	guS2DEmuBgRect1Cyc(Gfx **, uObjBg *);
#endif

#ifdef _LANGUAGE_C_PLUS_PLUS
}
#endif
#endif /* GS2DEX_H */
#endif
/*======== End of gs2dex.h ========*/
